package logic

import (
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
	"yundian/internel/app/models/paysetting"
	"yundian/internel/pkg/wechatpay"
)

func (logic *OrderLogic) HandleWxCancelOrderByYd(tradeNo string) error {

	wc := &paysetting.PaySetting{
		Id:               0,
		AppId:            "wx829e281c013a66e2",
		AppSecret:        "f4835de26bbc2db26fb4104aa13efe43",
		//AppId:            "wx9ab574042f46a487",
		//AppSecret:        "8038d10ec8546545954ceaa78aae3008",
		MchId:            "1600369044",
		ApiKey:           "1D6ABC370832B6BC4A204AA5E78DAC8C",
		ApiKeyV3:         "1D6ABC370832B6BC4A204AA5E78DAC8C",
		ServerId:         "00002000000000160017544128115466",
		SerialNo:         "1D6ABC370832B6BC4A204AA5E78DAC8CD78BDF5D",
		Status:           0,
		DepositNotifyUrl: "",
		ScoreNotifyUrl:   "",
		RefundNotifyUrl:  "",
		CertsPath:        "./configs/certs/yd/apiclient_cert.pem",
		ApiclientKeyPath: "./configs/certs/yd/apiclient_key.pem",
		TypeName:         "",
	}

	// 查询微信订单信息
	//resultData, err := YdApiQueryPayScoreOrder(tradeNo, wc) // 查询微信订单
	//if err != nil {
	//	logs.Info("微信订单查询失败", err.Error())
	//}
	//log.Println("打印测试数据，查询微信订单结果", resultData)

	// 查询订单
	//apiData := wxpay.NewPayData()
	//apiData.Set("transaction_id", orderInfo.OutTradeNo)
	//payClient := wxpay.NewPayClient(nil)
	//respData, err := wxpay.ApiOrderQuery(payClient, apiData)
	//if err != nil {
	//	zap.L().Error("error order query - 微信订单查询失败")
	//	return errors.New("error order query - 微信订单查询失败")
	//}
	//log.Println("打印测试数据，查询微信订单结果", respData)
	//if respData.Get("return_code") == wxpay.RCSuccess &&
	//	respData.Get("result_code") == wxpay.RCSuccess {
	//}

	// 取消订单
	apiParam := wechatpay.NewPayData()
	//apiParam.Set("out_order_no", tradeNo)
	apiParam.Set("appid", wc.AppId)
	apiParam.Set("service_id", wc.ServerId)
	apiParam.Set("reason", "用户投诉")
	respCancelData, err := YdApiCancelPayScoreOrder(apiParam, tradeNo, wc)
	if err != nil {
		return err
	}
	log.Println("打印测试数据，撤销微信订单结果", respCancelData)
	return nil
}


// 取消支付分订单   文档: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter3_3.shtml
// v3/payscore/serviceorder/{out_order_no}/cancel
func YdApiCancelPayScoreOrder(apiData *wechatpay.PayData, outOrderNo string, wc *paysetting.PaySetting) (respData *wechatpay.PayData, err error) {

	url := wechatpay.StrJoin("/v3/payscore/serviceorder", "/", outOrderNo, "/cancel")
	authorization, err := YdGenerateToken("POST", url, apiData.ToJson(), wc)
	if err != nil {
		return nil, err
	}

	client := NewYdTlsClient()

	url = wechatpay.StrJoin("https://api.mch.weixin.qq.com", url)
	respData, err = client.Post(url, map[string]string{
		"Content-Type":  "application/json; charset=utf-8",
		"Accept":        "application/json",
		"Authorization": authorization,
	}, apiData.ToJson())
	log.Println("打印测试数据----取消支付分订单--- ApiCancelPayScoreOrder-respData", respData)

	return
}

// 查询微信支付分订单 文档：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter3_2.shtml
func YdApiQueryPayScoreOrder(outOrderNo string, wc *paysetting.PaySetting) (respData *wechatpay.PayData, err error) {
	param := fmt.Sprintf("service_id=%s&out_order_no=%s&appid=%s", wc.ServerId,
		outOrderNo, wc.AppId)
	url := wechatpay.StrJoin("/v3/payscore/serviceorder", "?", param)
	authorization, err := YdGenerateToken("GET", url, "", wc)
	if err != nil {
		return nil, err
	}

	client := NewYdTlsClient()

	url = wechatpay.StrJoin("https://api.mch.weixin.qq.com", url)
	log.Println("打印测试数据 ApiQueryPayScoreOrder-url", url)

	respData, err = client.Get(url, map[string]string{
		"Content-Type":  "application/json; charset=utf-8",
		"Accept":        "application/json",
		"User-Agent":    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
		"Authorization": authorization,
	})
	log.Println("打印测试数据----查询微信支付分订单----- ApiQueryPayScoreOrder-respData", respData)
	return
}

func YdGenerateToken(method, url, body string, wc *paysetting.PaySetting) (token string, err error) {
	mchid := wc.MchId                                                      // 服务商商户号
	nonceStr := strings.ToUpper(wechatpay.RandomStr(32))                             // 32位随机字符串
	timestamp := wechatpay.TimeStamp()                                               // 时间戳
	serialNo := wc.SerialNo                                                // 商户证书序列号
	signature, err := YdGenerateSign(method, url, timestamp, nonceStr, body) //生成签名
	if err != nil {
		return "", err
	}

	authorization := fmt.Sprintf(`%s mchid="%s",nonce_str="%s",signature="%s",timestamp="%s",serial_no="%s"`,
		"WECHATPAY2-SHA256-RSA2048", mchid, nonceStr, signature, timestamp, serialNo)

	log.Println("打印测试数据--构建的 Token ", authorization)

	return authorization, err
}

func YdGenerateSign(method, url, timestamp, nonceStr, body string) (sign string, err error) {
	targetStr := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n",
		method, url, timestamp, nonceStr, body)
	log.Println("打印测试数据-构建的 签名串 ", targetStr)
	log.Println("打印测试数据-签名串长度", len(targetStr))
	sign, err = YdSHA256WithRsaBase64(targetStr)
	return
}


func YdSHA256WithRsaBase64(origData string) (sign string, err error) {
	block, _ := ioutil.ReadFile("./configs/certs/yd/apiclient_key.pem") // 商户私钥
	privateKey, err := YdParsePrivateKey(block)                        // 解析私钥
	if err != nil {
		return "", err
	}

	h := sha256.New()
	h.Write([]byte(origData))
	digest := h.Sum(nil) // 附加

	s, _ := rsa.SignPKCS1v15(nil, privateKey, crypto.SHA256, digest) // 加密
	sign = base64.StdEncoding.EncodeToString(s)                      // base64编码
	return
}

func YdParsePrivateKey(pemData []byte) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode(pemData)
	if block == nil || block.Type != "PRIVATE KEY" {
		return nil, errors.New("未能解码PUBLIC KEY")
	}

	priInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	return priInterface.(*rsa.PrivateKey), nil
}

func NewYdTlsClient() *wechatpay.PayClient {
	certs, _ := tls.LoadX509KeyPair("./configs/certs/yd/apiclient_cert.pem", "./configs/certs/yd/apiclient_key.pem")
	client := &http.Client{
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				RootCAs:      nil,
				Certificates: []tls.Certificate{certs},
			},
		},
	}
	return wechatpay.NewPayClient(client)
}



//{
//"appid": "wxd678efh567hg6787",
//"mchid": "1230000109",
//"out_order_no": "1230000109",
//"service_id": "500001",
//"order_id": "15646546545165651651"
//}
//
//
//错误码公共错误码
//状态码 	错误码 	描述 	解决方案
//500 	SYSTEM_ERROR 	系统错误 	5开头的状态码都为系统问题，请使用相同参数稍后重新调用
//400 	PARAM_ERROR 	参数错误 	根据错误提示，传入正确参数
//403 	NO_AUTH 	商户信息不合法 	登录商户平台核对，传入正确信息
//429 	FREQUENCY_LIMITED 	频率超限 	请求量不要超过接口调用频率限制
//400 	INVALID_REQUEST 	请求参数符合参数格式，但不符合业务规则 	请确认相同单号是否使用了不同的参数
//404 	ORDER_NOT_EXIST 	订单不存在 	确认入参，传入正确单据
//400 	INVALID_ORDER_STATE 	单据状态错误 	确认操作是否符合流程
//400 	ORDER_CANCELED 	单据已取消 	当前状态无需操作
//400 	ORDER_DONE 	订单已完成 	当前状态无需操作

//100411616616380626
//map[appid:wx829e281c013a66e2 mchid:1600369044 order_id:1000000000202103251143320781178 out_order_no:100411616616380626 service_id:00002000000000160017544128115466]







func (logic *OrderLogic) HandleWxCancelOrderByZm(tradeNo string) error {

	wc := &paysetting.PaySetting{
		Id:               0,
		AppId:            "wxf4240c791f428e08",
		AppSecret:        "26826fa63d67519dd95103e31214cfd7",

		MchId:            "1604377294",
		ApiKey:           "166966ACD2FD9DD0BCD090C4E26D5AF1",
		ApiKeyV3:         "166966ACD2FD9DD0BCD090C4E26D5AF1",
		ServerId:         "00002000000000160808732231865413",
		SerialNo:         "166966ACD2FD9DD0BCD090C4E26D5AF16F3BF647",
		Status:           0,
		DepositNotifyUrl: "",
		ScoreNotifyUrl:   "",
		RefundNotifyUrl:  "",
		CertsPath:        "./configs/certs/zm/apiclient_cert.pem",
		ApiclientKeyPath: "./configs/certs/zm/apiclient_key.pem",
		TypeName:         "",
	}


	// 取消订单
	apiParam := wechatpay.NewPayData()
	//apiParam.Set("out_order_no", tradeNo)
	apiParam.Set("appid", wc.AppId)
	apiParam.Set("service_id", wc.ServerId)
	apiParam.Set("reason", "用户投诉")
	respCancelData, err := ZmApiCancelPayScoreOrder(apiParam, tradeNo, wc)
	if err != nil {
		return err
	}
	log.Println("打印测试数据，撤销微信订单结果", respCancelData)
	return nil
}


// 取消支付分订单   文档: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter3_3.shtml
// v3/payscore/serviceorder/{out_order_no}/cancel
func ZmApiCancelPayScoreOrder(apiData *wechatpay.PayData, outOrderNo string, wc *paysetting.PaySetting) (respData *wechatpay.PayData, err error) {

	url := wechatpay.StrJoin("/v3/payscore/serviceorder", "/", outOrderNo, "/cancel")
	authorization, err := ZmGenerateToken("POST", url, apiData.ToJson(), wc)
	if err != nil {
		return nil, err
	}

	client := NewZmTlsClient()

	url = wechatpay.StrJoin("https://api.mch.weixin.qq.com", url)
	respData, err = client.Post(url, map[string]string{
		"Content-Type":  "application/json; charset=utf-8",
		"Accept":        "application/json",
		"Authorization": authorization,
	}, apiData.ToJson())
	log.Println("打印测试数据----取消支付分订单--- ApiCancelPayScoreOrder-respData", respData)

	return
}

// 查询微信支付分订单 文档：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter3_2.shtml
func ZmApiQueryPayScoreOrder(outOrderNo string, wc *paysetting.PaySetting) (respData *wechatpay.PayData, err error) {
	param := fmt.Sprintf("service_id=%s&out_order_no=%s&appid=%s", wc.ServerId,
		outOrderNo, wc.AppId)
	url := wechatpay.StrJoin("/v3/payscore/serviceorder", "?", param)
	authorization, err := ZmGenerateToken("GET", url, "", wc)
	if err != nil {
		return nil, err
	}

	client := NewZmTlsClient()

	url = wechatpay.StrJoin("https://api.mch.weixin.qq.com", url)
	log.Println("打印测试数据 ApiQueryPayScoreOrder-url", url)

	respData, err = client.Get(url, map[string]string{
		"Content-Type":  "application/json; charset=utf-8",
		"Accept":        "application/json",
		"User-Agent":    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
		"Authorization": authorization,
	})
	log.Println("打印测试数据----查询微信支付分订单----- ApiQueryPayScoreOrder-respData", respData)
	return
}

func ZmGenerateToken(method, url, body string, wc *paysetting.PaySetting) (token string, err error) {
	mchid := wc.MchId                                                      // 服务商商户号
	nonceStr := strings.ToUpper(wechatpay.RandomStr(32))                             // 32位随机字符串
	timestamp := wechatpay.TimeStamp()                                               // 时间戳
	serialNo := wc.SerialNo                                                // 商户证书序列号
	signature, err := ZmGenerateSign(method, url, timestamp, nonceStr, body) //生成签名
	if err != nil {
		return "", err
	}

	authorization := fmt.Sprintf(`%s mchid="%s",nonce_str="%s",signature="%s",timestamp="%s",serial_no="%s"`,
		"WECHATPAY2-SHA256-RSA2048", mchid, nonceStr, signature, timestamp, serialNo)

	log.Println("打印测试数据--构建的 Token ", authorization)

	return authorization, err
}

func ZmGenerateSign(method, url, timestamp, nonceStr, body string) (sign string, err error) {
	targetStr := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n",
		method, url, timestamp, nonceStr, body)
	log.Println("打印测试数据-构建的 签名串 ", targetStr)
	log.Println("打印测试数据-签名串长度", len(targetStr))
	sign, err = ZmSHA256WithRsaBase64(targetStr)
	return
}


func ZmSHA256WithRsaBase64(origData string) (sign string, err error) {
	block, _ := ioutil.ReadFile("./configs/certs/zm/apiclient_key.pem") // 商户私钥
	privateKey, err := ZmParsePrivateKey(block)                        // 解析私钥
	if err != nil {
		return "", err
	}

	h := sha256.New()
	h.Write([]byte(origData))
	digest := h.Sum(nil) // 附加

	s, _ := rsa.SignPKCS1v15(nil, privateKey, crypto.SHA256, digest) // 加密
	sign = base64.StdEncoding.EncodeToString(s)                      // base64编码
	return
}

func ZmParsePrivateKey(pemData []byte) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode(pemData)
	if block == nil || block.Type != "PRIVATE KEY" {
		return nil, errors.New("未能解码PUBLIC KEY")
	}

	priInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	return priInterface.(*rsa.PrivateKey), nil
}

func NewZmTlsClient() *wechatpay.PayClient {
	certs, _ := tls.LoadX509KeyPair("./configs/certs/zm/apiclient_cert.pem", "./configs/certs/zm/apiclient_key.pem")
	client := &http.Client{
		Timeout: 10 * time.Second,
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				RootCAs:      nil,
				Certificates: []tls.Certificate{certs},
			},
		},
	}
	return wechatpay.NewPayClient(client)
}
















